﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using AutoMapper;
using AzureDiagMon.Common;
using AzureDiagMon.Common.Dtos;
using AzureDiagMon.Common.Helpers;
using AzureDiagMon.Model;

namespace AzureDiagMon.Services
{
    public partial class DataStoreService
    {
        private bool useXmlCache = true;

        private static IQueryable<WadLogEntry> GetWadLogEntries(StorageAccountDto storageAccount, IModelsContainer dtx, EventFilter filter)
        {
            //Consider filtering on EventTickCount field (long). It could be faster
            var startDate = filter.StartDate.HasValue ? filter.StartDate.Value.ToUniversalTime() : (DateTime?)null;
            var endDate = filter.EndDate.HasValue ? filter.EndDate.Value.ToUniversalTime() : (DateTime?)null;
            var levels = filter.Levels != null ? filter.Levels.Cast<int>().ToArray() : new int[0];

            var result = dtx.WadLogEntrySet
                .Where(f => f.StorageAccountId == storageAccount.Id
                            && (!startDate.HasValue || f.Timestamp >= startDate.Value)
                            && (!endDate.HasValue || f.Timestamp <= endDate.Value)
                            && levels.Any(l => f.Level == l));

            return result;
        }

        public IQueryable<WadLogEntryDto> GetLogEntries(StorageAccountDto storageAccount, EventFilter filter)
        {
            var dtx = IoC.Get<IModelsContainer>();
            return GetWadLogEntries(storageAccount, dtx, filter)
                   .OrderByDescending(f => f.RowKey)
                   .OrderByDescending(f => f.PartitionKey)
                   .Select(Mapper.Map<WadLogEntry, WadLogEntryDto>)
                   .AsQueryable();
        }

        public int GetLogEntryCount(StorageAccountDto storageAccount, EventFilter filter)
        {
            using (var dtx = IoC.Get<IModelsContainer>())
            {
                return GetWadLogEntries(storageAccount, dtx, filter).Count();
            }
        }

        public IList<WadLogEntryDto> ListLogEntries(StorageAccountDto storageAccount, EventFilter filter)
        {
            using (var dtx = IoC.Get<IModelsContainer>())
            {
                return GetWadLogEntries(storageAccount, dtx, filter).ToList()
                    .Select(Mapper.Map<WadLogEntry, WadLogEntryDto>)
                    .ToList();
            }
        }

        public IList<WadLogEntryDto> ListLogEntries(StorageAccountDto storageAccount, EventFilter filter, int startIndex, int count)
        {
            using (var dtx = IoC.Get<IModelsContainer>())
            {
                Debug.WriteLine(string.Format("ListLogEntries {1} items from {0} ", startIndex, count));
                return GetWadLogEntries(storageAccount, dtx, filter)
                            .OrderByDescending(f => f.RowKey)
                            .OrderByDescending(f => f.PartitionKey)
                            .Skip(startIndex)
                            .Take(count)
                            .ToList()
                            .Select(Mapper.Map<WadLogEntry, WadLogEntryDto>)
                            .ToList();
            }
        }

        public void AddLogEntries(StorageAccountDto storageAccount, IEnumerable<WadLogEntryTableEntity> entries)
        {
            if (storageAccount == null)
                throw new ArgumentNullException("storageAccount");

            if (entries == null)
                throw new ArgumentNullException("entries");

            //if (useXmlCache)
            //{
            //    new CacheFile<WadLogEntryTableEntity>(entries);
            //    return;
            //}

            int cnt = 0;
            using (var dtx = IoC.Get<IModelsContainer>())
            {
                var sw = Stopwatch.StartNew();
                //var entryKeys = entries.AsParallel().Select(f => String.Concat(f.PartitionKey, f.RowKey)).ToArray();
                //var existing = dtx.WadLogEntrySet.Where(f => entryKeys.Contains(f.PartitionKey + f.RowKey))
                //                .ToList()
                //                .AsParallel()
                //                .Select(f => entries.Single(e => e.PartitionKey == f.PartitionKey && e.RowKey == f.RowKey))
                //                .ToList();
                //sw.Stop();
                //Debug.WriteLine("Get existing items: {0} ms", sw.ElapsedMilliseconds);
                //sw = Stopwatch.StartNew();
                //var newEntries = entries.Except(existing).ToList();
                foreach (var wadLogEntryTableEntity in entries)
                {
                    var entity = wadLogEntryTableEntity;
                    //if (!dtx.WadLogEntrySet.Any(f => f.PartitionKey == entity.PartitionKey
                    //                               && f.RowKey == entity.RowKey))
                    //{
                    var dbentity = Mapper.Map<WadLogEntryTableEntity, WadLogEntry>(entity);
                    dbentity.StorageAccountId = storageAccount.Id;
                    dtx.WadLogEntrySet.AddObject(dbentity);
                    cnt++;
                    //}
                }
                if (cnt > 0)
                {
                    dtx.SaveChanges();
                    OnLogEntriesChanged(EventArgs.Empty);
                }
                sw.Stop();
                Debug.WriteLine(string.Format("Inserting {0} entries done. Items added: {1} Elapsed: {2} ms", entries.Count(), cnt, sw.ElapsedMilliseconds));
            }
        }

    }
}
